package com.iothub.netty4.nettypack;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PreDestroy;

/**
 * 通过配置类启动
 */
//public class StartNetty implements Runnable {

public class StartNetty {

    public static int timeout = 30;

    private static final Logger logger = LoggerFactory.getLogger(StartNetty.class);
    /**
     * 使用nio模式的标志，当此标志为1时，即使用nio模式，当此模块为0时，即使用epoll模式
     */
    private static final boolean epollEnable = false;

    /**
     * server port
     */
    int serverPort = 6000;

    //TcpServerHandler serverHandler = new TcpServerHandler();
    EventLoopGroup bossGroup = null;
    EventLoopGroup workerGroup = null;
    ServerBootstrap serverBootstrap = null;
    ChannelFuture future = null;
    ChannelFuture toolFuture = null;


    public StartNetty(int sPort) {
        this.serverPort = sPort;
    }

    @PreDestroy
    public void stop() {
        if (future != null) {
            toolFuture.channel().close().addListener(ChannelFutureListener.CLOSE);
            toolFuture.awaitUninterruptibly();
            future.channel().close().addListener(ChannelFutureListener.CLOSE);
            future.awaitUninterruptibly();
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            future = null;
            toolFuture = null;
            logger.info(" 服务关闭 ");
        }
    }

    private void initEventLoopGroup() {
        if(epollEnable) {
            logger.info("采用 epoll 模式!");
            bossGroup = new EpollEventLoopGroup();
            workerGroup = new EpollEventLoopGroup();
        } else {
            logger.info("采用 nio 模式!");
            bossGroup = new NioEventLoopGroup();
            workerGroup = new NioEventLoopGroup();
        }
    }

    private void initServerBootstrap() {

        logger.info("初始化 server bootstrap!");

        serverBootstrap = new ServerBootstrap();

        serverBootstrap.group(bossGroup, workerGroup)
                //指定所使用的NIO传输Channel
                //.channel(NioServerSocketChannel.class)
                //使用指定的端口设置套接字地址
                //.localAddress(new InetSocketAddress(serverPort))
                // 添加一个EchoServerHandler到Channle的ChannelPipeline
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        /*socketChannel.pipeline().addLast("idlestatus",new IdleStateHandler(
                                timeout,
                                0,
                                0));*/

                        //添加netty空闲超时检查机制
                        //1.读空闲 (一定时间没有从服务器啦数据)(超过一定时间就发送对应的事件消息)
                        //2/写空闲超时(一定时间没有向Netty服务器写数据)
                        //3.读写空闲

                        //第一个参数设置未读时间，第二个参数设置为未写时间，第三个为都未进行操作的时间
                        //单位秒
                        socketChannel.pipeline().addLast("idlestatus",
                                new IdleStateHandler(
                                        30,
                                        45,
                                        60));

                        //添加超时检查机制--事件消息捕获类
                        //socketChannel.pipeline().addLast(new HeatBeatHandler());

                        //EchoServerHandler被标注为@shareable,所以我们可以总是使用同样的案例
                        socketChannel.pipeline().addLast(new TcpServerHandler());
                        //socketChannel.pipeline().addLast()


                    }
                });


        if (epollEnable) {
            serverBootstrap.channel(EpollServerSocketChannel.class);
        } else {
            serverBootstrap.channel(NioServerSocketChannel.class);
        }
    }

    private void initChannelFuture() throws InterruptedException {
        logger.info("绑定端口:" + this.serverPort);
        //future = serverBootstrap.bind(this.serverPort).sync();
        future = serverBootstrap.bind(this.serverPort).sync();
        toolFuture = serverBootstrap.bind(this.serverPort+1).sync();
    }

    public void start() {

        initEventLoopGroup();
        initServerBootstrap();

        try {
            initChannelFuture();

            //启动超时线程，改为用netty中的超时机制
            //StartTimeoutThread();

            // 获取Channel的CloseFuture，并且阻塞当前线程直到它完成
            //future.channel().closeFuture().sync();

            future.channel().closeFuture().addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    //通过回调只关闭自己监听的channel
                    future.channel().close();
                }
            });

            toolFuture.channel().closeFuture().addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    toolFuture.channel().close();
                }
            });
            //System.out.println("OK!");
            logger.info("netty start ok!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 优雅的关闭EventLoopGroup，释放所有的资源
            //bossGroup.shutdownGracefully(); //这里一定要注释，因为上面没有阻塞了，不注释的话，这里会直接关闭的
            //workerGroup.shutdownGracefully();
        }
    }

    /***
     * 启动发送线程
     */
    private void startSendThread(){
        Runnable st = new SendHandler();
        Thread tst = new Thread(st);
        tst.setDaemon(true);
        tst.setName("tst");
        tst.start();
    }

}
